
package stcu.control;

import stcu.*;
import stcu.forms.*;
import stcu.robjects.*;
import com.nvlled.route.*;
import java.util.concurrent.ConcurrentHashMap;

import java.util.*;
import java.io.IOException;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.event.*;
import java.text.SimpleDateFormat;

public class ControlledMainForm extends MainForm
    implements Group.Listener {

    private JFrame self = this;
    private Group defaultGroup;
    private DefaultListModel<String> userListModel;
    private DefaultListModel<GroupAdd> groupListModel;
    private Map<String, GroupAdd> groups;
    private Client client;
    private Map<String, ChatForm> chatForms;

    private FileManager fileMan;
    private FileManagerForm fileManForm;

    public ControlledMainForm(Group group, Client client) {
		setTitle("Shut the Chat Up");
        configFrame();

        chatForms = new ConcurrentHashMap<String, ChatForm>();
        this.client = client;
        defaultGroup = group;
        messageLogText.setEditable(false);
        userListModel = new DefaultListModel<String>();
        groupListModel = new DefaultListModel<GroupAdd>();
        groups = new HashMap<String, GroupAdd>();

        userList.setModel(userListModel);
        groupList.setModel(groupListModel);

        handleButtons();
        defaultGroup.addListener(this);
        monitorGroups();

        group.listMembers();
        listGroups();

        DefaultCaret caret = (DefaultCaret)messageLogText.getCaret();
        caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
		
		jScrollPane1.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		messageLogText.setLineWrap(true);
		
		ClientAuth auth = client.getAuth();
		messageLogText.append("Joined " + auth.getServerName() + "\n\n");

        final Account account = auth.getAccount();
        //userName.setText(account.getName());
        //userName.setEditable(false);

        try {
            fileMan = new FileManager(client.getRouter(), group);
            fileManForm = new FileManagerForm(fileMan);
            fileMan.listFiles();
        } catch (IOException e) {
            JOptionPane.showMessageDialog(self, "Filemanager failed.");
        }
    }

    private void logout() {
        ClientAuth auth = client.getAuth();
        fileMan.stop();
        defaultGroup.leave();
        auth.logout();
    }

    private void configFrame() {
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                logout();
            }
        });
    }

    private void listGroups() {
        ObjectRouter router = client.getRouter();
        router.deliver(new GroupList(), "default");
    }

    private void handleButtons() {
        fileTransferButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                fileManForm.setVisible(true);
            }
        });
        sendButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String message = messageText.getText();
				if (message.isEmpty()){
					return;
				}
                messageText.setText("");
                defaultGroup.send(message);
            }
        });

        clearButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                messageLogText.setText("");
            }
        });

		messageText.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String message = messageText.getText();
				if (message.isEmpty()){
					return;
				}
                messageText.setText("");
                defaultGroup.send(message);
			}
		});
		
        createButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                final GroupAccess access = client.getAccess();
                final ObjectRouter router = client.getRouter();
                ClientAuth auth = client.getAuth();
                final ControlledCreateGroupForm createForm = new ControlledCreateGroupForm(self);
                final Account account = auth.getAccount();

                ActionListener listener = new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        final String title = createForm.getGroupTitle();
						if(title.isEmpty()){
							return;
						} else {
                        try {
                            Group group = access.create(account, title);
                            final ChatForm form = new ControlledChatForm(router, group);
                            addForm(group.getId(), form);
                            SwingUtilities.invokeLater(new Runnable() {
                                public void run() {
                                    createForm.setVisible(false);
                                    form.setVisible(true);
									form.setTitle(title + " - Group Chat");
                                }
                            });
                        } catch (GroupOperationException err) {
                            JOptionPane.showMessageDialog(self, err.getMessage());
                        }}
                    }
                };
                createForm.setCreateHandler(listener);
                createForm.setVisible(true);
            }
        });
        joinButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                final GroupAdd groupInfo = (GroupAdd) groupList.getSelectedValue();
                if (groupInfo == null) {
                    JOptionPane.showMessageDialog(null, "Select a group then click Join", "No group selected", JOptionPane.WARNING_MESSAGE);
                    return;
                }

                final ChatForm existingForm = chatForms.get(groupInfo.getGroupId());
                if (existingForm != null) {
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            existingForm.setVisible(true);
                            existingForm.toFront();
                        }
                    });
                    return;
                }

                joinButton.setEnabled(false);
                GroupAccess access = client.getAccess();
                ClientAuth auth = client.getAuth();
                ObjectRouter router = client.getRouter();

                try {
                    Group group = access.join(auth.getAccount(), groupInfo.getGroupId());
                    final ChatForm form = new ControlledChatForm(router, group); 
                    addForm(groupInfo.getGroupId(), form);
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            form.setVisible(true);
                        }
                    });
                } catch (GroupOperationException err) {
                    JOptionPane.showMessageDialog(self, err.getMessage());
                }
                joinButton.setEnabled(true);
            }
        });
        logoutButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                logout();
            }
        });
    }

    private void addForm(final String gid, ChatForm form) {
        chatForms.put(gid, form);
        form.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosed(WindowEvent e) {
                chatForms.remove(gid);
            }
        });
    }

    private void monitorGroups() {
        ObjectReceiver<GroupAdd> receiverAdd = new ObjectReceiver<GroupAdd>() {
            public void receive(GroupAdd group) {
                ObjectRouter router = client.getRouter();
                AddressTable table = router.getTable();
                table.store(group.getGroupId(), group.getAddress());
                groups.put(group.getGroupId(), group);
                groupListModel.addElement(group);
            }
        };
        ObjectReceiver<GroupDel> receiverDel = new ObjectReceiver<GroupDel>() {
            public void receive(GroupDel group) {
                groups.remove(group.getGroupId());
                groupListModel.removeElement(group);
                String id = group.getGroupId();
                ChatForm form = chatForms.get(id);
                if (form != null) {
                    if (form.isVisible()) {
                        JOptionPane.showMessageDialog(self, "Group Deleted " + id);
                    }
                    form.dispose();
                }
            }
        };
        ObjectRouter router = client.getRouter();
        router.subscribe(GroupAdd.class, receiverAdd);
        router.subscribe(GroupDel.class, receiverDel);
    }

    public void messageReceived(GroupMessage message) {
		// Timestamp TODO Here:
		Calendar cal = Calendar.getInstance();
		cal.getTime();
		SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss aa");
		
		String line = message.getSender() + ": " +
            message.getMessage();
        messageLogText.append(line+"\n\n");
        messageLogText.append("\t"+"\t"+"\t"+"\t"+"Received "+sdf.format(cal.getTime())+"\n");
    }

    public void memberJoined(final MemberAdd member) {
        final String name = member.getName();
        if (member.isNewMember()) {
            String line = name + " has logged in";
            messageLogText.append(line+"\n\n");

        }
        if (! userListModel.contains(name)) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    userListModel.addElement(name);
                }
            });
        }
    }

    public void memberLeft(final MemberDel member) {
        String line = member.getName() + " has logged out";
        messageLogText.append(line+"\n\n");
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                userListModel.removeElement(member.getName());
            }
        });

        //String name = member.getName();
        //GroupDemux demux = client.getAccess().getDemux();
        //for (Group group: demux.getSubscribedGroups()) {
        //    group.receive(new GroupLeave(name, group.getId()));
        //}
    }
}
